﻿using SDL2;
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Threading;

namespace THZFrm {
    class VideoPlayer {
        public delegate int GetData(IntPtr data, int nWidth, int nHeight);      //获取待显示的YUV数据

        #region SDL显示相关
        private IntPtr pWindow;
        private IntPtr pRenderer;
        private IntPtr pTexture;            // 用于绘制图像
        private byte[] colorBK = new byte[4] { 255, 255, 255, 255 }; // 底色，RGBA
        private SDL.SDL_Rect rcImage;       // 输入图像的宽高
        private SDL.SDL_Rect rcDisplay;     // 显示区域的宽高
        private SDL.SDL_Rect rcScale;       // 用于缩放输入图像
        #endregion

        public GetData getData = null;
        private bool bShowLogo = true;

        private readonly object mutex = new object();

        private int nThreadCtl = 0;

        public VideoPlayer() {

            getData = new GetData(UpdateScreen);

            Reset();

            Thread thread = new Thread(new ThreadStart(EventHandle));
            thread.Start();
        }

        public void Reset() {
            if(pWindow == IntPtr.Zero) {
                rcDisplay.w = 1280;
                rcDisplay.h = 720;
                pWindow = SDL.SDL_CreateWindow(
                    "传入视频",
                    SDL.SDL_WINDOWPOS_UNDEFINED,
                    SDL.SDL_WINDOWPOS_UNDEFINED,
                    rcDisplay.w,
                    rcDisplay.h,
                    SDL.SDL_WindowFlags.SDL_WINDOW_OPENGL | SDL.SDL_WindowFlags.SDL_WINDOW_RESIZABLE);
                pRenderer = SDL.SDL_CreateRenderer(pWindow, -1, SDL.SDL_RendererFlags.SDL_RENDERER_ACCELERATED);
            }
            if(!bShowLogo) {
                ShowPicture("logo.bmp");
            }
            bShowLogo = true;
        }

        public void ShowPicture(string path) {
            if(pWindow == IntPtr.Zero) {
                Reset();
            }
            SDL.SDL_RenderClear(pRenderer);
            SDL.SDL_SetRenderDrawColor(pRenderer, colorBK[0], colorBK[1], colorBK[2], colorBK[3]);
            SDL.SDL_RenderFillRect(pRenderer, ref rcDisplay);

            IntPtr surface = SDL.SDL_LoadBMP(path);
            IntPtr texture = SDL.SDL_CreateTextureFromSurface(pRenderer, surface);
            
            int pw, ph, ww = rcDisplay.w, wh = rcDisplay.h;
            SDL.SDL_QueryTexture(texture, out _, out _, out pw, out ph);
            SDL.SDL_Rect rc;
            if(ph > wh || pw > ww) {
                // 图片的宽或高大于窗口高度，根据长宽比来决定左右还是上下留空
                if(ww * ph > wh * pw) {
                    rc.h = wh;
                    rc.w = (int)((float)wh / ph * pw);
                    rc.y = 0;
                    rc.x = (ww - rc.w) / 2;
                } else {
                    rc.h = (int)((float)ww / pw * ph);
                    rc.w = wh;
                    rc.y = (wh - rc.h) / 2;
                    rc.x = 0;
                }
            } else {
                rc.w = pw;
                rc.h = ph;
                rc.x = (ww - pw) / 2;
                rc.y = (wh - ph) / 2;
            }

            SDL.SDL_RenderCopy(pRenderer, texture, IntPtr.Zero, ref rc);
            SDL.SDL_RenderPresent(pRenderer);

            SDL.SDL_FreeSurface(surface);
            SDL.SDL_DestroyTexture(texture);
        }

        // 事件处理函数，

        public void EventHandle() {
            nThreadCtl = 1;
            SDL.SDL_Event sdlevent;
            do {
                //SDL.SDL_WaitEvent(out sdlevent); // 为什么检测不到事件？
                SDL.SDL_WaitEventTimeout(out sdlevent, 100);
                switch(sdlevent.type) {
                    case SDL.SDL_EventType.SDL_WINDOWEVENT:
                        if(sdlevent.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_SHOWN) {
                            UpdateWindowSize();
                            if(bShowLogo) {
                                ShowPicture("logo.bmp");
                            }
                        }
                        if(sdlevent.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_RESIZED) {
                            UpdateWindowSize();
                            if(bShowLogo) {
                                ShowPicture("logo.bmp");
                            }
                        }
                        break;
                    case SDL.SDL_EventType.SDL_QUIT:
                        SDL.SDL_DestroyWindow(pWindow);
                        pWindow = IntPtr.Zero;
                        break;
                    case SDL.SDL_EventType.SDL_KEYDOWN:

                        break;
                    default:
                        break;
                }
            } while(nThreadCtl == 1);
        }

        // 关闭窗口
        public void Close() {
            nThreadCtl = 0;
            SDL.SDL_Quit();
        }

        public int UpdateScreen(IntPtr data, int nW, int nH) {
            bShowLogo = false;
            if(rcImage.w != nW || rcImage.h != nH) {
                SetImageSize(nW, nH);
            }
            lock(mutex) {
                // 先把上一帧的内容清空再绘制下一帧
                SDL.SDL_RenderClear(pRenderer);
                SDL.SDL_SetRenderDrawColor(pRenderer, colorBK[0], colorBK[1], colorBK[2], colorBK[3]);

                SDL.SDL_UpdateTexture(pTexture, ref rcImage, data, rcImage.w);
                SDL.SDL_RenderCopy(pRenderer, pTexture, ref rcImage, ref rcScale);
                SDL.SDL_RenderPresent(pRenderer);
            }
            
            return 0;
        }

        //图像的显示区域发生变化时，需要更新。更新后是否需要重新刷新图像，待定
        public void UpdateWindowSize() {
            int w, h;
            SDL.SDL_GetWindowSize(pWindow, out w, out h);
            if(w != rcDisplay.w || h != rcDisplay.h) {
                lock(mutex) {
                    rcDisplay.w = w;
                    rcDisplay.h = h;

                    // 窗口修改后renderer会失效，需重新创建
                    SDL.SDL_DestroyRenderer(pRenderer);
                    pRenderer = SDL.SDL_CreateRenderer(pWindow, -1, SDL.SDL_RendererFlags.SDL_RENDERER_ACCELERATED);
                    
                    SDL.SDL_DestroyTexture(pTexture);
                    pTexture = SDL.SDL_CreateTexture(pRenderer, SDL.SDL_PIXELFORMAT_IYUV, (int)SDL.SDL_TextureAccess.SDL_TEXTUREACCESS_STREAMING, rcImage.w, rcImage.h);

                    UpdateScaleRect();
                }
            }
        }

        public void SetImageSize(int w, int h) {
            if(w != rcImage.w || h != rcImage.h) {
                lock(mutex) {
                    rcImage.w = w;
                    rcImage.h = h;
                    SDL.SDL_DestroyTexture(pTexture);
                    pTexture = SDL.SDL_CreateTexture(pRenderer, SDL.SDL_PIXELFORMAT_IYUV, (int)SDL.SDL_TextureAccess.SDL_TEXTUREACCESS_STREAMING, rcImage.w, rcImage.h);
                    UpdateScaleRect();
                }
            }
        }

        private void UpdateScaleRect() {
            if(rcImage.w == 0 || rcImage.h == 0) {
                return;
            }
            
            if((rcImage.w != rcDisplay.w) || (rcImage.h != rcDisplay.h)) {
                //  避免整数除法的影响，a/b > c/d  ==> a*d > b*c
                if(rcDisplay.w * rcImage.h > rcImage.w * rcDisplay.h) {
                    // 左右留空
                    rcScale.h = rcDisplay.h;
                    rcScale.w = (int)((float)rcScale.h / rcImage.h * rcImage.w);
                    rcScale.x = (rcDisplay.w - rcScale.w) / 2;
                    rcScale.y = 0;
                } else {
                    // 上下留空
                    rcScale.w = rcDisplay.w;
                    rcScale.h = (int)((float)rcScale.w / rcImage.w * rcImage.h);
                    rcScale.x = 0;
                    rcScale.y = (rcDisplay.h - rcScale.h) / 2;
                }
            } else {
                rcScale = rcDisplay;
            }
        }

        [DllImport("user32.dll")]
        private static extern IntPtr SetParent(IntPtr child, IntPtr newParent);
        [DllImport("user32.dll")]
        private static extern IntPtr ShowWindow(IntPtr handle, int command);

    }
}
